"""
    进程间的通讯
    本文件包含两个简短示例：
    1. 使用 multiprocessing.Queue 在生产者/消费者之间传递数据（推荐用于多个生产者/消费者）。
    2. 使用 multiprocessing.Pipe 在父子进程间进行双向通信（点对点）。
"""
from multiprocessing import Process, Queue, Pipe, current_process
import multiprocessing as mp
import time
import os

def queue_producer(q, count=5):
    """生产者：把整数放入队列，最后放入 None 作为结束标记。"""
    for i in range(count):
        item = f"{current_process().name}-item-{i}"
        print(f"Producer put: {item}")
        q.put(item)
        time.sleep(0.2)
    q.put(None)  # 发送结束标志

def queue_consumer(q):
    """消费者：从队列读取，直到收到 None 为止。"""
    while True:
        item = q.get()
        if item is None:
            print("Consumer got sentinel, exiting.")
            break
        print(f"Consumer got: {item}")
        time.sleep(0.3)

def queue_example():
    """示例：Queue 用于进程间安全传递数据。"""
    q = Queue()
    p_prod = Process(target=queue_producer, args=(q, 6), name="Producer")
    p_cons = Process(target=queue_consumer, args=(q,), name="Consumer")

    p_prod.start()
    p_cons.start()

    p_prod.join()
    # 生产者退出后，消费者会在接收到 sentinel 后退出
    p_cons.join()
    print("Queue example finished.\n")

def pipe_worker(conn):
    """Pipe 子进程端：接收消息并回送确认。"""
    try:
        while True:
            msg = conn.recv()  # 阻塞等待父进程发送
            if msg == "exit":
                conn.send(f"{current_process().name} exiting")
                break
            print(f"Child recv: {msg}")
            conn.send(f"ack:{msg}")
    except EOFError:
        pass
    finally:
        conn.close()

def pipe_example():
    """示例：Pipe 用于双向点对点通信（速度快，但不适合多个进程共享）。"""
    parent_conn, child_conn = Pipe()
    p = Process(target=pipe_worker, args=(child_conn,), name="PipeChild")
    p.start()

    # 父进程发送若干消息并等待子进程回复
    for i in range(3):
        msg = f"msg-{i}"
        print(f"Parent send: {msg}")
        parent_conn.send(msg)
        # 等待子进程的应答
        reply = parent_conn.recv()
        print(f"Parent recv: {reply}")

    # 结束子进程的循环
    parent_conn.send("exit")
    print("Parent recv final:", parent_conn.recv())

    parent_conn.close()
    p.join()
    print("Pipe example finished.\n")

if __name__ == "__main__":
    # 在 macOS/部分环境下显式设置启动方式更稳健
    try:
        mp.set_start_method("spawn", force=False)
    except RuntimeError:
        pass

    print("PID", os.getpid(), "- Running IPC examples\n")
    queue_example()
    pipe_example()